﻿using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using Newtonsoft.Json.Linq;
using NHibernate;
using Web.Extensions;
using Web.HelperClasses.AvatarService;
using Web.Model;

namespace Web.Controllers
{
    public class VkontakteLoginController : OAuthLoginController
    {
		protected override string TokenManagerKey
		{
			get { return "VkontakteTokenManager"; }
		}
		protected override string CustomerKey
		{
			get { return "vkontakteAppID"; }
		}
		protected override string CustomerSecret
		{
			get { return "vkontakteAppSecret"; }
		}

        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Head)]
        public override ActionResult SendRequest(Uri callbackUri)
        {
            if (!String.IsNullOrEmpty(Request.QueryString["error"]))
                return
                    Content(String.Format("{0} {1}", Request.QueryString["error"], Request.QueryString["error_description"]));

            //если ещё не аутентифицировались
            var tokenManager = GetTokenManager();
            var scope = "notify";
            var first = String.Format(
            "http://api.vkontakte.ru/oauth/authorize?client_id={0}&scope={1}&redirect_uri={2}&response_type=code",
            tokenManager.ConsumerKey,
            scope,
            Uri.EscapeDataString(Url.ActionAbsolute("Callback") + "?callbackUri=" + Uri.EscapeDataString(callbackUri.ToString()))
            );
            return Redirect(first);
        }

        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Head)]
        public override ActionResult Callback(Uri callbackUri)
        {
            var code = Request.QueryString["code"];
            //если уже есть код аутентификации, осталось только получить access_token
            if (!String.IsNullOrEmpty(code))
            {
                var tokenManager = GetTokenManager();
                var second =
                    String.Format(
                        "https://api.vkontakte.ru/oauth/access_token?client_id={0}&client_secret={1}&code={2}",
                        tokenManager.ConsumerKey,
                        tokenManager.ConsumerSecret,
                        code);

                var req =
                    (HttpWebRequest)WebRequest.Create(second);
                var response = req.GetResponse();
                var responseStream = response.GetResponseStream();

                if (responseStream == null)
                    return Content("Error in reading response");
                var content = new StreamReader(responseStream).ReadToEnd();
                JObject json = JObject.Parse(content);
                JToken errorJToken;
                if (json.TryGetValue("error", out errorJToken))
                {
                    var error = errorJToken.Value<string>();
                    var errorDescription = json["error_description"].Value<string>();
                    return Content(String.Format("Error:{0}<br />Error description:{1}", error, errorDescription));
                }

                JToken accessTokenJToken, userIdJToken;
                if (!json.TryGetValue("access_token", out accessTokenJToken) || !json.TryGetValue("user_id", out userIdJToken))
                    return Content("Bad response");
                var userId = userIdJToken.Value<int>();
                var accessToken = accessTokenJToken.Value<string>();

                AccountInfo accountInfo;
                try
                {
                    accountInfo = new VkontakteAccountInfo(accessToken, userId);
                }
                catch (InvalidDataException ex)
                {
                    return Content(ex.Message);
                }
                CreateOrAuthorizeUser(accountInfo);
            }
            return Redirect(callbackUri != null ? callbackUri.ToString() : Url.Action("Index", "Home"));
        }

        public VkontakteLoginController(ISession session, IUserSession userSession, AvatarService avatarService)
            : base(session, userSession, avatarService)
        {
        }
    }

    internal class VkontakteAccountInfo : AccountInfo
    {
        public VkontakteAccountInfo(string accessToken, int userId)
        {
            var third =
                    String.Format(
                        "https://api.vkontakte.ru/method/getProfiles?uid={0}&access_token={1}&fields=photo_big",
                        userId,
                        accessToken);

            var req =
                (HttpWebRequest)WebRequest.Create(third);
            var response = req.GetResponse();
            var responseStream = response.GetResponseStream();

            if (responseStream == null) 
                throw new InvalidDataException("Error in reading response");
            var content = new StreamReader(responseStream).ReadToEnd();
            var json = JObject.Parse(content);
            JToken firstNameJToken, lastNameJToken, photoJToken;
            JToken responseJToken = json["response"].Children().First();
            firstNameJToken = responseJToken.SelectToken("first_name", false);
            lastNameJToken = responseJToken.SelectToken("last_name", false);
            photoJToken = responseJToken.SelectToken("photo_big", false);
            if (firstNameJToken == null || lastNameJToken == null)
                throw new InvalidDataException("Bad response");
            Name = firstNameJToken.Value<string>() + " " + lastNameJToken.Value<string>();

            if (photoJToken != null)
            {
                Photo = photoJToken.Value<string>();
            }
            //todo: исправить!! vkontakte не даёт email, так что нужно придумать альтернативу
            Email = userId + "@vkontakte.ru";
            AccountSource = AccountSource.Vkontakte;
        }

    }
}
